//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.ComponentModel;
using System.Drawing;
using System.Workflow.ComponentModel;
using Microsoft.Research.DataLayer;
using TridentContext;

namespace Microsoft.Research.ScientificWorkflow.Activities
{
    [Name("Data Product Writer")]
    [Description("Creates/Updates the data product in the registry and sets the value.")]
    [WorkflowCategory("Data")]
    public class DataProductWriterActivity : System.Workflow.ComponentModel.Activity
    {
        private Connection registryConnection;

        #region Dependency Properties

        public static DependencyProperty DataProdIdProperty = DependencyProperty.Register("DataProdId",
            typeof(string), typeof(DataProductWriterActivity));

        [InputParam]
        [Name("DataProduct Id")]
        [Description("String representing the GUID of the data product.")]
        public string DataProdId
        {
            get { return ((string)(base.GetValue(DataProductWriterActivity.DataProdIdProperty))); }
            set { base.SetValue(DataProductWriterActivity.DataProdIdProperty, value); }
        }

        public static DependencyProperty DataProdNameProperty = DependencyProperty.Register("DataProdName",
            typeof(string), typeof(DataProductWriterActivity));

        [RequiredInputParam]
        [Name("DataProduct Name")]
        [Description("String representing the name of the data product.")]
        public string DataProdName
        {
            get { return ((string)(base.GetValue(DataProductWriterActivity.DataProdNameProperty))); }
            set { base.SetValue(DataProductWriterActivity.DataProdNameProperty, value); }
        }

        public static DependencyProperty ParamTypeProperty = DependencyProperty.Register("ParamType",
            typeof(string), typeof(DataProductWriterActivity));

        [RequiredInputParam]
        [Name("DataProduct Type")]
        [Description("String representing the type of the data product.")]
        public string ParamType
        {
            get { return ((string)(base.GetValue(DataProductWriterActivity.ParamTypeProperty))); }
            set { base.SetValue(DataProductWriterActivity.ParamTypeProperty, value); }
        }

        public static DependencyProperty StringValueProperty = DependencyProperty.Register("StringValue",
            typeof(string), typeof(DataProductWriterActivity));

        [InputParam]
        [Name("String Value")]
        [Description("String value of the data product.")]
        public string StringValue
        {
            get { return ((string)(base.GetValue(DataProductWriterActivity.StringValueProperty))); }
            set { base.SetValue(DataProductWriterActivity.StringValueProperty, value); }
        }

        public static DependencyProperty ImageValueProperty = DependencyProperty.Register("ImageValue",
            typeof(Image), typeof(DataProductWriterActivity));

        [InputParam]
        [Name("Image Value")]
        [Description("Integer value of the data product.")]
        public Image ImageValue
        {
            get { return ((Image)(base.GetValue(DataProductWriterActivity.ImageValueProperty))); }
            set { base.SetValue(DataProductWriterActivity.ImageValueProperty, value); }
        }

        public static DependencyProperty ByteArrayValueProperty = DependencyProperty.Register("ByteArrayValue",
            typeof(byte[]), typeof(DataProductWriterActivity));

        [InputParam]
        [Name("Byte Array Value")]
        [Description("Byte Array value of the data product.")]
        public byte[] ByteArrayValue
        {
            get { return ((byte[])(base.GetValue(DataProductWriterActivity.ByteArrayValueProperty))); }
            set { base.SetValue(DataProductWriterActivity.ByteArrayValueProperty, value); }
        }

        #endregion

        #region Overridden Methods

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            Context ctx = Context.Get();
            this.registryConnection = ctx.Connection.Clone();
            this.registryConnection.Open();

            string dpType = this.ParamType;

            Guid dataProdId = (true == string.IsNullOrEmpty(this.DataProdId)) ?
                Guid.NewGuid() : new Guid(this.DataProdId);
            DataProduct dp = GetDataProduct(dataProdId, this.DataProdName, dpType);
            dp.ProducedBy = ctx.WFInstance;

            ActivitySequence sequence = ctx.GetActivitySequence(this.Name);
            if (sequence != null)
            {
                dp.CreatorActivity = sequence;
            }

            GetDPValue(ref dp, dpType);

            // Create a Tracking event signifying that a dataproduct has been created.
            this.TrackData("DataProductID", ((IObject)dp).ID.ToString());

            // Close the registry Connection.
            if (this.registryConnection != null)
            {
                this.registryConnection.Close();
                this.registryConnection = null;
            }

            return ActivityExecutionStatus.Closed;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Return an existing data product if found else create a new
        /// one and send back.
        /// </summary>
        /// <param name="dataProdId"></param>
        /// <param name="dataProdName"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private DataProduct GetDataProduct(Guid dataProdId, string dataProdName, string type)
        {
            if (String.IsNullOrEmpty(type))
            {
                throw new ArgumentNullException("Dataproduct Type");
            }
            if (String.IsNullOrEmpty(dataProdName))
            {
                throw new ArgumentNullException("Dataproduct Name");
            }
            try
            {
                DataProduct dp = DataProduct.Load(dataProdName, this.registryConnection);
                if (((IObject)dp).ID == dataProdId)
                {
                    return dp;
                }
            }
            catch (Exception)
            {
            }
            DataProduct newDp = DataProduct.Create(dataProdName, type, this.registryConnection);

            return newDp;
        }

        private void GetDPValue(ref DataProduct dp, string dpType)
        {
            if ((0 == dpType.ToLower().CompareTo("text/richtext")) ||
                   (0 == dpType.ToLower().CompareTo("text/plain")) ||
                   (0 == dpType.ToLower().CompareTo("text/html")) ||
                   (0 == dpType.ToLower().CompareTo("text/xml")))
            {
                if (string.IsNullOrEmpty(this.StringValue))
                {
                    throw new ArgumentNullException("StringValue", "StringValue input is null or empty");
                }

                dp.ContentsAsString = this.StringValue;
            }
            else if ((0 == dp.Type.ToLower().CompareTo("image/gif"))
                    || (0 == dp.Type.ToLower().CompareTo("image/jpg"))
                    || (0 == dp.Type.ToLower().CompareTo("image/bmp"))
                    || (0 == dp.Type.ToLower().CompareTo("image/png")))
            {
                if (this.ImageValue == null)
                {
                    throw new ArgumentNullException("ImageValue", "ImageValue input is null");
                }

                dp.ContentsAsImage = this.ImageValue;
            }
            else
            {
                if (this.ByteArrayValue == null)
                {
                    throw new ArgumentNullException("ByteArrayValue", "ByteArrayValue input is null");
                }

                dp.Contents = this.ByteArrayValue;
            }
        }

        private string GetLabel()
        {
            object[] attributes = this.GetType().GetCustomAttributes(typeof(NameAttribute), false);
            if (attributes.Length != 0)
            {
                return (attributes[0] as NameAttribute).Label;
            }

            return this.Name;
        }

        #endregion
    }
}
